﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Media;

namespace RouteTest
{
    public enum enumNodeType
    {
        Source,
        Dest,
        Etc,
    }
     public enum enumMode
        {
            Node,
            Edge,
            AGV
        }
    public enum enumDrawEdgeStatus
    {
        Start,
        Drawing,
        Finish,
    }

    public struct stNode
    {
        public int id;
        public string name;
        public Point position;
        public enumNodeType type;
        public int OcuupiedAGV;
    }

    public struct stEdge
    {
        public int id;
        public int distance;
        public stNode source;
        public stNode dest;
    }

    public struct stVehicle
    {
        public int id;
        public Point position;
    }

    /// <summary>
    /// MainWindow.xaml에 대한 상호 작용 논리
    /// </summary>
    public partial class MainWindow : Window
    {
        public enumMode _Mode = enumMode.Node;

        public NodeShapeList _NodesShape;
        public EdgeShapeList _EdgesShape;
        public VehicleShapeList _VehicleShapeList;

        public MainWindow()
        {
            InitializeComponent();

            _NodesShape = new NodeShapeList(NodeCanvas);
            _EdgesShape = new EdgeShapeList(NodeCanvas);
            _VehicleShapeList = new VehicleShapeList(NodeCanvas);
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            InitControl();
        }

        void InitControl()
        {
        }
   
        private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
        {
           
        }

        void DrawNode(Point point)
        {
            if (_NodesShape.IsOnMouseOver() >= 0) return;

            stNode newNode = new stNode();
            newNode.id = _NodesShape.Count;
            newNode.name = newNode.id.ToString();
            newNode.position = point;
            newNode.type = enumNodeType.Etc;

            NodeShape newNodeShape = new NodeShape(newNode, NodeCanvas);
            newNodeShape.SetUnselected();
            newNodeShape.OnNodeMove += new delegateNodeMove(newNodeShape_OnNodeMove);

            _NodesShape.AddNode(newNodeShape);

            UpdateCombo();

            lbNode.Content = "Node =" + _NodesShape.Count.ToString();

            System.Diagnostics.Debug.WriteLine("노드 추가");
        }

        void DrawEdgeStart()
        {
            int selectedNode = _NodesShape.IsOnMouseOver();
            if (selectedNode >= 0)
            {
                stEdge newEdge = new stEdge();
                newEdge.id = _EdgesShape.Count;
                newEdge.distance = 0;
                newEdge.source = _NodesShape[selectedNode]._Node;

                EdgeShape newEdgeShape = new EdgeShape(newEdge, NodeCanvas);
                newEdgeShape._DrawStatus = enumDrawEdgeStatus.Start;

                _EdgesShape.AddEdge(newEdgeShape);

                _NodesShape._IsStartDrawEdge = true;

                System.Diagnostics.Debug.WriteLine("Edge 그리기 시작");
            }
        }

        void DrawEdgeEnd()
        {
            int drawingEdge = _EdgesShape.GetDrawingEdgeID();
            if (drawingEdge >= 0)
            {
                int destNode = _NodesShape.IsOnMouseOver();

                if (destNode >= 0 && _EdgesShape[drawingEdge]._Edge.source.id != _NodesShape[destNode]._Node.id)
                {
                    _EdgesShape[drawingEdge].SetDest(_NodesShape[destNode]);
                    _NodesShape._IsStartDrawEdge = false;
                    System.Diagnostics.Debug.WriteLine("Edge 그리기 완료");
                }
                else
                {
                    _NodesShape._IsStartDrawEdge = false;

                    NodeCanvas.Children.Remove(_EdgesShape[drawingEdge]._Line);
                    NodeCanvas.Children.Remove(_EdgesShape[drawingEdge]._Label);

                    _EdgesShape.RemoveAt(drawingEdge);

                    System.Diagnostics.Debug.WriteLine("Edge 그리기 취소");
                }
                _NodesShape.AllNodeUnselect();
            }
        }

        void DrawVehicle(Point point)
        {
                if (_VehicleShapeList.IsOnMouseOver() >= 0) return;

                stVehicle newVehicle = new stVehicle();
                newVehicle.id = _VehicleShapeList.Count;
                newVehicle.position = point;

                VehicleShape newVehicleShape = new VehicleShape(newVehicle, NodeCanvas);

                _VehicleShapeList.AddVehicle(newVehicleShape);
        }

        private void NodeCanvas_MouseDown(object sender, MouseButtonEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                switch (_Mode)
                {
                    case enumMode.Node:
                        DrawNode(e.GetPosition(NodeCanvas));
                        break;
                    case enumMode.Edge:
                        if (!_NodesShape._IsStartDrawEdge)
                            DrawEdgeStart();
                        else
                            DrawEdgeEnd();
                        break;
                    case enumMode.AGV:
                        DrawVehicle(e.GetPosition(NodeCanvas));
                        break;
                }
            }
            else
            {
                if (_NodesShape.IsOnMouseOver() == -1 && _VehicleShapeList.IsOnMouseOver() == -1 && _EdgesShape.IsOnMouseOver() == -1)
                {
                    switch (_Mode)
                    {
                        case enumMode.Node:
                            _Mode = enumMode.Edge;
                            rbEdge.IsChecked = true;
                            break;
                        case enumMode.Edge:
                            if (_NodesShape._IsStartDrawEdge)
                                DrawEdgeEnd();
                            _Mode = enumMode.Node;
                            rbNode.IsChecked = true;
                            break;
                        case enumMode.AGV:
                            //_Mode = enumMode.Node;
                            //rbNode.IsChecked = true;
                            break;
                    }
                }
            }
        }

        void newNodeShape_OnNodeMove(object sender, object value)
        {
                for(int i = 0 ; i<_EdgesShape.Count; i++)
                {
                    if (_EdgesShape[i]._Edge.source.id == ((NodeShape)sender)._Node.id)
                    {
                        _EdgesShape[i].MoveSource(((NodeShape)sender)._Node.position.X, ((NodeShape)sender)._Node.position.Y);
                        System.Diagnostics.Debug.WriteLine("Source Node 이동");
                    }
                    else if (_EdgesShape[i]._Edge.dest.id == ((NodeShape)sender)._Node.id)
                    {
                        _EdgesShape[i].MoveDest(((NodeShape)sender)._Node.position.X, ((NodeShape)sender)._Node.position.Y);

                        System.Diagnostics.Debug.WriteLine("Dest Node 이동");
                    }
                }
        }

        private void NodeCanvas_MouseMove(object sender, MouseEventArgs e)
        {
        }

        private void NodeCanvas_MouseUp(object sender, MouseButtonEventArgs e)
        {
        }

        void UpdateCombo()
        {
            cbSource.Items.Clear();
            cbDest.Items.Clear();

            foreach (NodeShape node in _NodesShape)
            {
                cbDest.Items.Add(node._Node.name);
                cbSource.Items.Add(node._Node.name);
            }
            cbSource.SelectedIndex = 0;
            cbDest.SelectedIndex = 0;
        }

        private void btnCompute_Click(object sender, RoutedEventArgs e)
        {
            PathFinder pathFinder = new PathFinder();

            long starttime = DateTime.Now.Ticks;
            int distance;
            int[,] metrix = ConvertMetrix();
            int[] path ;

            int requiredNode = _NodesShape.HasRequiredNode() ;
            if (requiredNode != -1)
            {
                path = pathFinder.SearchShortestPath(metrix, cbSource.SelectedIndex, requiredNode, cbDest.SelectedIndex, out distance);
            }
            else
            {
                path = pathFinder.SearchShortestPath(metrix, cbSource.SelectedIndex, cbDest.SelectedIndex, out distance);
            }
            long endtime = DateTime.Now.Ticks;
            lblTime.Content = ((float)((float)(endtime - starttime) / (float)10000000)).ToString() + " sec";

            DisplayPath(path, distance);
        }

        void DisplayPath(int[] path , int distance)
        {
            if (path.Length == 0)
            {
                lblPoint.Content = "no Path";
                _EdgesShape.AllUnselected();
                return;
            }

            lblPoint.Content = "";

            for(int i = 0 ; i<path.Length; i++)
            {
                if (i != path.Length - 1)
                {
                    lblPoint.Content += path[i].ToString() + "→";
                }
                else
                {
                    lblPoint.Content += path[i].ToString() ;
                }
            }

            lblPoint.Content += ",  Distance : " + distance.ToString();

            _EdgesShape.SelectEdges(path);
        }

        public int INFINITY = 15000;
        private int[,] ConvertMetrix()
        {
            int[,] result = new int[_NodesShape.Count, _NodesShape.Count];

            for (int i = 0; i < _NodesShape.Count; i++)
            {
                for (int j = 0; j < _NodesShape.Count; j++)
                {
                    result[i, j] = INFINITY;
                }
            }

            for (int i = 0; i < _EdgesShape.Count; i++)
            {
                bool destLock = false;

                for (int j = 0; j < _NodesShape.Count; j++)
                {
                    if (_NodesShape[j]._RouteType == enumNodeRouteType.Avoidance)
                    {
                        if (_EdgesShape[i]._Edge.dest.id == _NodesShape[j]._Node.id)
                        {
                            destLock = true;
                            break;
                        }
                    }
                }

                if(destLock)
                    result[_EdgesShape[i]._Edge.source.id, _EdgesShape[i]._Edge.dest.id] = INFINITY;
                else
                    result[_EdgesShape[i]._Edge.source.id, _EdgesShape[i]._Edge.dest.id] = _EdgesShape[i]._Edge.distance;
            }

            return result;
        }       
        private void rbNode_Checked(object sender, RoutedEventArgs e)
        {
            if (_NodesShape != null)
            {
                _NodesShape.AllNodeUnselect();
                _NodesShape.UnlockNodeMove();
                _VehicleShapeList.LockNodeMove();
            }

            _Mode = enumMode.Node;
        }

        private void rbEdge_Checked(object sender, RoutedEventArgs e)
        {
            if (_NodesShape != null)
            {
                _NodesShape.AllNodeUnselect();
                _NodesShape.LockNodeMove();
                _VehicleShapeList.LockNodeMove();
            }

            _Mode = enumMode.Edge;
        }

        private void btnReset_Click(object sender, RoutedEventArgs e)
        {
            _NodesShape.Clear();
            _EdgesShape.Clear();
            _VehicleShapeList.Clear();

            NodeCanvas.Children.Clear(); ;
        }

        private void rbVehicle_Checked(object sender, RoutedEventArgs e)
        {
            if (_NodesShape != null)
            {
                _NodesShape.AllNodeUnselect();
                _NodesShape.LockNodeMove();
                _VehicleShapeList.UnlockNodeMove();
            }

            _Mode = enumMode.AGV;

        }
    }
}
